package cn.mw.cmdb.service.impl;

import cn.hutool.extra.spring.SpringUtil;
import cn.mw.cmdb.entity.ModelSpecificationInfo;
import cn.mw.cmdb.entity.ModelTemplateInfo;
import cn.mw.cmdb.entity.ModelVendorInfo;
import cn.mw.cmdb.enums.OperatorTypeDescEnum;
import cn.mw.cmdb.exception.UploadFileEmptyException;
import cn.mw.cmdb.exception.UploadFileFormatException;
import cn.mw.cmdb.mongoMapper.ModelVendorMapper;
import cn.mw.cmdb.param.*;
import cn.mw.cmdb.service.ModelVendorService;
import cn.mw.cmdb.util.CMDBTool;
import cn.mw.cmdb.util.ExcelUtils;
import cn.mw.components.mongodb.entity.CriteriaOpsType;
import cn.mw.components.mongodb.entity.SearchParam;
import cn.mw.components.mongodb.entity.SubCondition;
import cn.mw.components.mongodb.tool.CriteriaWrapper;
import cn.mw.log.client.LogClientSimple;
import cn.mw.log.enums.BusinessLogType;
import cn.mw.log.enums.LogLevel;
import cn.mw.microMonitorCommon.constant.Constants;
import cn.mw.microMonitorCommon.security.dto.MwUser;
import cn.mw.microMonitorCommon.security.utils.SecurityUtils;
import cn.mw.microMonitorCommon.util.DateUtils;
import cn.mw.microMonitorCommon.util.SpringUtils;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import com.google.common.base.Strings;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import static cn.mw.cmdb.enums.PageDescEnum.ModelManufacture;
import static cn.mw.cmdb.enums.PageDescEnum.ModelTemplate;
import static cn.mw.cmdb.util.ValConvertUtil.intValueConvert;
import static cn.mw.microMonitorCommon.util.FileNameCheckUtils.isValidFileName;

@Slf4j
public class ModelVendorServiceImpl extends ModelBaseServiceImpl<ModelVendorInfo, VendorIdsParam> implements ModelVendorService {

    private ModelVendorMapper modelVendorMapper;
    private CmdbServiceManage cmdbServiceManage;
    private LogClientSimple logClientSimple;

    public ModelVendorServiceImpl(ModelVendorMapper modelVendorMapper, CmdbServiceManage cmdbServiceManage) {
        this.modelVendorMapper = modelVendorMapper;
        this.cmdbServiceManage = cmdbServiceManage;
    }

    public ModelVendorServiceImpl() {
        this.logClientSimple = SpringUtil.getBean(LogClientSimple.class);
    }

    public static final String ID = "modelVendor";


    private String imgPathStr = "file.url";

    //厂商图标上传目录
    static final String MODULE = "vendor-upload";



    @Override
    public ModelVendorInfo genObject() {
        return new ModelVendorInfo();
    }

    @Override
    Object doAdd(ModelVendorInfo param) {
        CMDBTool.initCreateInfo(param);
        return modelVendorMapper.insert(param);
    }

    @Override
    boolean doUpdate(ModelVendorInfo param) throws Exception {
        Query query = new Query(CriteriaWrapper.where(ModelVendorInfo::getId).is(param.getId()));
        CMDBTool.initUpdateInfo(param);
        Update update = CMDBTool.genMongoUpdate(param, null, null);
        CMDBTool.updateFirst(modelVendorMapper, query, update);
        return true;
    }

    @Override
    boolean doRemove(ModelVendorInfo param) throws Exception {
        CMDBTool.remove(modelVendorMapper,param.getId(),ModelVendorInfo.class,true);
        return true;
    }

    @Override
    Object doBatchAdd(Object params) {
        if (params!=null && params instanceof List) {
            List<ModelVendorInfo> params1 = (List<ModelVendorInfo>) params;
            for(ModelVendorInfo info : params1){
                CMDBTool.initCreateInfo(info);
            }
            modelVendorMapper.insertAll(params1);
        }
        return true;
    }

    @Override
    boolean doBatchUpdate(Object params) {
        return false;
    }

    @Override
    public ModelVendorInfo doSelectById(Object obj) {
        ModelVendorInfo info = new ModelVendorInfo();
        if (obj instanceof ModelVendorInfo) {
            String id = ((ModelVendorInfo) obj).getId();
            info = modelVendorMapper.findById(id);
        }
        return info;
    }
    public List<ModelVendorInfo> doSelectByIds(List<String> ids) throws Exception {
        Query query = genQueryByIds(ids);
        query.addCriteria(CriteriaWrapper.where(ModelVendorInfo::getDelFlag).is(false));
        List<ModelVendorInfo> list = modelVendorMapper.find(query);
        return list;
    }

    @Override
    List<ModelVendorInfo> doSelectList(Object obj) throws Exception {
        VendorSearchParam searchParam = (VendorSearchParam) obj;
        //获取参数值对对应属性类型,并生成查询条件
        Query query = genQuery(searchParam, null);
        query.addCriteria(CriteriaWrapper.where(ModelVendorInfo::getDelFlag).is(false));
        List<ModelVendorInfo> ret = CMDBTool.selectList(ModelVendorInfo.class, modelVendorMapper, query, searchParam);
        ModelSpecificationServiceImpl specificationService = (ModelSpecificationServiceImpl) cmdbServiceManage.getModelService(ModelSpecificationServiceImpl.ID);

        List<ModelSpecificationInfo> allSpecificationInfos = specificationService.getAllSpecificationInfos();
        Map<String, Long> collect = allSpecificationInfos.stream().filter(s -> !Strings.isNullOrEmpty(s.getVendorId())).collect(Collectors.groupingBy(ModelSpecificationInfo::getVendorId, Collectors.counting()));
        for(ModelVendorInfo vendorInfo : ret){
            if(collect!=null && collect.containsKey(vendorInfo.getId())){
                vendorInfo.setCount(intValueConvert(collect.get(vendorInfo.getId())));
            }
        }



        return ret;
    }

    @Override
    boolean doBatchRemove(VendorIdsParam params) throws Exception {
        CMDBTool.remove(modelVendorMapper,params.getIds(),ModelVendorInfo.class,true);
        return true;
    }

    /**
     * 厂商名称重复性校验
     *
     * @param info
     * @return
     */
    @Override
    public boolean checkVendorName(ModelVendorInfo info) throws Exception {
        Query query = new Query(Criteria.where(CMDBTool.getFieldName(ModelVendorInfo::getVendorCN)).is(info.getVendorCN()));
        query.addCriteria(CriteriaWrapper.where(ModelVendorInfo::getDelFlag).is(false));
        List<ModelVendorInfo> list = modelVendorMapper.find(query);
        if (!CollectionUtils.isEmpty(list)) {
            return true;
        }
        return false;
    }

    @Override
    public String uploadIcon(MultipartFile multipartFile) throws Exception {
        String imgPath = SpringUtils.getPropertiesValue(imgPathStr);
        String fileNameInTable = "";
        if (multipartFile.isEmpty()) {
            throw new UploadFileEmptyException();
        }
        //获取文件名
        String fileName = multipartFile.getOriginalFilename();
        boolean validFileName = isValidFileName(fileName);
        if(!validFileName){
            throw  new UploadFileFormatException();
        }

        //文件重命名，防止重复
        fileName = System.currentTimeMillis() + fileName;
        File file = new File(new File(imgPath).getAbsolutePath() + File.separator + MODULE + File.separator + UUID.randomUUID());
        //检测是否存在目录
        String path = new File(imgPath).getAbsolutePath() + File.separator + MODULE + File.separator;
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        multipartFile.transferTo(file);
        //设置放到数据库字段的值
        fileNameInTable = fileName;
        return fileNameInTable;
    }



    /**
     * 获取模板对应的厂商列表
     */
    @Override
    public List<ModelVendorInfo> queryVendorByTemplate(String templateId) throws Exception {
        List<ModelVendorInfo> list = new ArrayList<>();
        if (Strings.isNullOrEmpty(templateId)) {
            //模板id为空，则查询所有厂商信息
            list = doSelectList(new VendorSearchParam());
            return list;
        }
        //模板id有数据，则根据模板id查询对应关联的厂商
        ModelTemplateServiceImpl modelService = (ModelTemplateServiceImpl) cmdbServiceManage.getModelService(ModelTemplateServiceImpl.ID);
        ModelTemplateInfo modelTemplateInfo = modelService.doSelectById(templateId);
        if (modelTemplateInfo != null) {
            Query query = new Query(Criteria.where(CMDBTool.getFieldName(ModelVendorInfo::getId)).is(modelTemplateInfo.getBrandId()));
            query.addCriteria(CriteriaWrapper.where(ModelVendorInfo::getDelFlag).is(false));
            list = modelVendorMapper.find(query);
        }
        return list;
    }

    @Override
    public List<ModelVendorInfo> queryVendorByTemplateName(String templateName) throws Exception {
        List<ModelVendorInfo> list = new ArrayList<>();
        if (Strings.isNullOrEmpty(templateName)) {
            //模板名称为空，则查询所有厂商信息
            list = doSelectList(new VendorSearchParam());
            return list;
        }

        //模板名称有数据，则根据模板名称查询对应关联的厂商
        ModelTemplateServiceImpl modelService = (ModelTemplateServiceImpl) cmdbServiceManage.getModelService(ModelTemplateServiceImpl.ID);
        TemplateSearchParam searchParam = new TemplateSearchParam();
        searchParam.addSubCondition(CMDBTool.getFieldName(ModelTemplateInfo::getTemplateName)
                , new SubCondition(CriteriaOpsType.is.name(), templateName));
        List<ModelTemplateInfo> modelTemplateList = modelService.doSelectList(searchParam);
        Set<String> collect = modelTemplateList.stream().map(ModelTemplateInfo::getBrandId).collect(Collectors.toSet());
        if (collect != null) {
            Query query = new Query(Criteria.where(CMDBTool.getFieldName(ModelVendorInfo::getId)).in(collect));
            query.addCriteria(CriteriaWrapper.where(ModelVendorInfo::getDelFlag).is(false));
            list = modelVendorMapper.find(query);
        }
        return list;
    }

    /**
     * 厂商导入
     *
     * @param file
     * @param response
     * @throws IOException
     */
    @Override
    public List<VendorExcelImportParam> importVendorByExcel(MultipartFile file, HttpServletResponse response) throws IOException {
        String fileName = file.getOriginalFilename();
        MwUser user = SecurityUtils.getUser();
        String loginName = user.getUsername();
        List<VendorExcelImportParam> failList = new ArrayList<>();
        if (null != fileName && (fileName.toLowerCase().endsWith(".xls") || fileName.toLowerCase().endsWith(".xlsx"))) {
            EasyExcel.read(file.getInputStream(), VendorExcelImportParam.class,
                    new VendorExcelImportListener(response, fileName, loginName, cmdbServiceManage,failList)).sheet().doRead();
        } else {
            log.error("没有传入正确的excel文件名", file);
        }
        return failList;
    }

    /**
     * 厂商导出
     *
     * @param fieldParam
     * @param response
     * @throws Exception
     */
    @Override
    public int exportVendorByExcel(VendorSearchParam fieldParam, HttpServletRequest request, HttpServletResponse response) throws Exception {
        int num = 0;
        ExcelWriter excelWriter = null;
        try {
            List<String> includeColumnFiledNames = new ArrayList<>(fieldParam.getHeader());
            if (CollectionUtils.isEmpty(includeColumnFiledNames)) {
                includeColumnFiledNames.add(CMDBTool.getFieldName(VendorExcelImportParam::getVendorCN));
                includeColumnFiledNames.add(CMDBTool.getFieldName(VendorExcelImportParam::getVendorUS));
                includeColumnFiledNames.add(CMDBTool.getFieldName(VendorExcelImportParam::getDescription));
            }
            excelWriter = ExcelUtils.getExcelWriter("exportModelVendor", response, VendorExcelImportParam.class);
            WriteSheet sheet = EasyExcel.writerSheet(0, "sheet" + 0)
                    .includeColumnFiledNames(includeColumnFiledNames)
                    .registerWriteHandler(ExcelUtils.writeTemplateStyle())
                    .registerWriteHandler(new VendorColumWithStyle())
                    .build();
            List<ModelVendorInfo> vendorInfoList;
            if (fieldParam.isExportTemp()) {//导出下载模板时，不需要数据，直接传空数据
                vendorInfoList = new ArrayList<>();
            } else {
                fieldParam.setOperation(SearchParam.keyword);
                fieldParam.setKeywordValue("");
                vendorInfoList = doSelectList(fieldParam);
            }
            excelWriter.write(vendorInfoList, sheet);
            if(CollectionUtils.isNotEmpty(vendorInfoList)){
                num = vendorInfoList.size();
            }
            log.info("导出成功");
        } catch (IOException e) {
            log.error("导出失败{}", e);
        } finally {
            if (null != excelWriter) {
                excelWriter.finish();
            }
        }
        return num;
    }

    private class VendorColumWithStyle extends AbstractColumnWidthStyleStrategy {
        @Override
        protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
            if (isHead) {
                writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), 6000);
            }
        }
    }

    /**
     * 新增异常日志记录
     *
     * @param param
     */
    public void addRecordMethod(Object param) {
        String name = "";
        if (param != null && param instanceof ModelVendorInfo) {
            ModelVendorInfo info = (ModelVendorInfo) param;
            name = info.getVendorCN();
        }
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.add.getCname() + ModelManufacture.getDesc(),
                        OperatorTypeDescEnum.add.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));
    }

    /**
     * 修改异常日志记录
     *
     * @param param
     */
    public void updateRecordMethod(Object param) {
        String name = "";
        if (param != null && param instanceof ModelVendorInfo) {
            ModelVendorInfo info = (ModelVendorInfo) param;
            name = info.getVendorCN();
        }
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.update.getCname() + ModelManufacture.getDesc(),
                        OperatorTypeDescEnum.update.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));
    }

    /**
     * 删除异常日志记录
     *
     * @param param
     */
    private void removeRecordMethod(Object param) {
        String name = "";
        if (param != null && param instanceof ModelVendorInfo) {
            ModelVendorInfo info = (ModelVendorInfo) param;
            name = info.getVendorCN();
        }
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.remove.getCname() + ModelManufacture.getDesc(),
                        OperatorTypeDescEnum.remove.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));

    }

    /**
     * 批量新增异常日志记录
     *
     * @param params
     */
    private void batchAddRecordMethod(Object params) {
        String name = "";
        if (params!=null && params instanceof List) {
            List<ModelVendorInfo> list = (List<ModelVendorInfo>) params;
            List<String> collect = list.stream().map(s -> s.getVendorCN()).collect(Collectors.toList());
            name = String.join(",", collect);
        }
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.batchAdd.getCname() + ModelManufacture.getDesc(),
                        OperatorTypeDescEnum.batchAdd.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));
    }

    /**
     * 批量修改异常日志记录
     *
     * @param param
     */
    private void batchUpdateRecordMethod(Object param) {

    }

    /**
     * 批量删除异常日志记录
     *
     */
    private void batchRemoveRecordMethod(Object params) throws Exception {
        String name = "";
        if (params != null && params instanceof VendorIdsParam) {
            List<String> ids = ((VendorIdsParam) params).getIds();
            List<ModelVendorInfo> infos = doSelectByIds(ids);
            List<String> collect = infos.stream().map(s -> s.getVendorUS()).collect(Collectors.toList());
            name = String.join(",", collect);
        }
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.batchRemove.getCname() + ModelManufacture.getDesc(),
                        OperatorTypeDescEnum.batchRemove.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));

    }



}
